package m.system.url;

import m.server.web.AppServerUtil;
import m.system.exception.MException;
import m.system.util.StringUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class UrlMarker {
	private static volatile Map<String,String> redirectMap;
	private static List<String> enableList;
	private static List<String> cachePathList;
	private static List<String> refererList;
	private static List<String> authorizationList;
	private static Map<String,String> requestHeaderMap;
	private static Map<String,String> responseHeaderMap;

	/**
	 * 获取一个有效的auth前缀
	 */
	public static String getAuth() {
		if(null!=authorizationList&& !authorizationList.isEmpty()) {
			return authorizationList.get(0);
		}
		return "";
	}
	/**
	 * 判断auth是否合法
	 */
	public static boolean isAuth(String auth){
		String[] arr=StringUtil.noSpace(auth).split(" ");
		for(String key : authorizationList) {
			if(arr[0].equals(key)) {
				return true; //如果授权前缀正确, 则不验证url 但后续action还需要自行验证.
			}
		}
		return false;
	}
	public static void initXML() throws ParserConfigurationException, MException, IOException, SAXException {
		redirectMap=new HashMap<>();
		enableList=new ArrayList<>();
		cachePathList=new ArrayList<>();
		refererList=new ArrayList<>();
		authorizationList=new ArrayList<>();
		requestHeaderMap=new HashMap<>();
		responseHeaderMap=new HashMap<>();
		InputStream is = AppServerUtil.loadConfig("config/urlmarker.xml");
		DocumentBuilderFactory domfac=DocumentBuilderFactory.newInstance();
		DocumentBuilder dombuilder;
		dombuilder = domfac.newDocumentBuilder();
		Document doc=dombuilder.parse(is);
		Element root=doc.getDocumentElement();
		NodeList urlType=root.getChildNodes();
		for(int i=0;i<urlType.getLength();i++){
			Node utype=urlType.item(i);
			if("redirect".equals(utype.getNodeName())){
				fillMap(utype,redirectMap);
			}
			if("enable".equals(utype.getNodeName())){
				fillList(utype,enableList);
			}
			if("cache".equals(utype.getNodeName())){
				fillList(utype,cachePathList);
			}
			if("referer".equals(utype.getNodeName())){
				fillList(utype,refererList);
			}
			if("authorization".equals(utype.getNodeName())){
				fillList(utype,authorizationList);
			}
			if("header".equals(utype.getNodeName())){
				fillHeadMap(utype,requestHeaderMap,responseHeaderMap);
			}
		}
	}
	private static void fillMap(Node utype, Map<String, String> map){
		NodeList urls=utype.getChildNodes();
        for (int i = 0; i < urls.getLength(); i++) {
            Node url = urls.item(i);
            if (null == url.getAttributes()) continue;
            Node attr = url.getAttributes().getNamedItem("tag");
            if (null != attr) {
                map.put(attr.getTextContent(), url.getTextContent());
            }
        }
    }
	private static void fillHeadMap(Node utype, Map<String, String> requestMap, Map<String, String> responseMap){
		NodeList urls=utype.getChildNodes();
		for (int i = 0; i < urls.getLength(); i++) {
			Node node = urls.item(i);
			if (null == node.getAttributes()) continue;
			Node attr = node.getAttributes().getNamedItem("name");
			if (null != attr) {
				if("request".equals(node.getNodeName())){
					requestMap.put(attr.getTextContent(), node.getTextContent());
				}else if("response".equals(node.getNodeName())){
					responseMap.put(attr.getTextContent(), node.getTextContent());
				}
			}
		}
	}
	private static void fillList(Node utype,List<String> list){
		NodeList urls=utype.getChildNodes();
        for (int i = 0; i < urls.getLength(); i++) {
            Node url = urls.item(i);
            if ("tag".equals(url.getNodeName())) {
                list.add(url.getTextContent());
            }
        }
    }
	public static boolean isDisabledUrl(String servletPath) {
		return servletPath.endsWith(".php")||servletPath.endsWith(".jsp")||servletPath.endsWith(".do")||servletPath.endsWith(".action");
	}
	/**
	 * 判断是否允许的url
	 *  servletPath
	 * 
	 */
	public static boolean isEnableUrl(String serverName,String servletPath,String referer,String authorization){
		if(!StringUtil.isSpace(authorization)) {
			if(isAuth(authorization)){
				return true; //如果授权前缀正确, 则不验证url 但后续action还需要自行验证.
			}
		}
		if(null!=referer) {//referer和serverName相同时直接过
			referer=referer.substring(referer.indexOf("//")+2);
			referer=referer.substring(0, referer.indexOf("/"));
			if(referer.contains(":")) referer=referer.substring(0, referer.indexOf(":"));
			if(referer.equals(serverName)) return true;
		}else if(servletPath.indexOf("/")==servletPath.lastIndexOf("/")){//跟目录不限制
			return true;
		}
		boolean b=false;
		for(String key : enableList){//允许列表
			if(servletPath.indexOf(key)==0){
				//b=true; break;
				return true;
			}
		}
		for(String key : redirectMap.keySet()){//自定义跳转列表
			if(servletPath.indexOf(key)==0||servletPath.indexOf(redirectMap.get(key))==0){
				b=true; break;
			}
		}
		if(b) {//判断主机是否可以访问
			for(String key : refererList){//允许列表
				if(null==referer&&serverName.indexOf(key)==0
						||null!=referer&&referer.indexOf(key)==0){
					return true;
				}
			}
		}
		return b;
	}
	/**
	 * 重定向
	 */
	public static String getRedirectUrl(String path){
		for(String tag : redirectMap.keySet()){
			if(path.indexOf(tag)==0){//&& !path.contains(".")path.lastIndexOf("/")<3&&
				return redirectMap.get(tag) + path.substring(path.indexOf(tag) + tag.length());
			}
		}
		return null;
	}


	/**
	 * url是否符合浏览器缓存机制
	 */
	public static boolean isCacheUrl(String url){
		for(String tag : cachePathList){
			if(url.indexOf(tag)==0){
				return true;
			}
		}
		return false;
	}

	public static Map<String, String> getRequestHeaderMap() {
		return requestHeaderMap;
	}

	public static Map<String, String> getResponseHeaderMap() {
		return responseHeaderMap;
	}
}
